import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:largefriends/config/lf_config.dart';
import 'package:largefriends/entity/entities/lf_site_key_entity.dart';
import 'package:largefriends/net/lf_token_interceptor.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

import '../entity/base/lf_base_entity.dart';
import '../entity/entities/two_factor_entity.dart';
import 'error_handle.dart';

enum Method { get, post, put, patch, delete, head }

extension MethodExtension on Method {
  String get value => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'][index];
}

class LfDio {
  factory LfDio() => _singleton;

  static final LfDio _singleton = LfDio._();

  static LfDio get instance => LfDio();

  static Dio _dio = Dio();

  Dio get dio => _dio;

  LfDio._() {
    final BaseOptions options = BaseOptions(
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 30),
      sendTimeout: const Duration(seconds: 60),

      /// dio默认json解析，这里指定返回UTF8字符串，自己处理解析。（可也以自定义Transformer实现）
      responseType: ResponseType.plain,
      contentType: Headers.formUrlEncodedContentType,
      validateStatus: (_) {
        // 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
        return true;
      },
      baseUrl: baseUrl,
    );
    _dio = Dio(options);

    /// 添加拦截器
    _dio.interceptors.add(LfTokenInterceptor());
    if (appOpenLog) {
      dio.interceptors.add(PrettyDioLogger(
          requestHeader: true,
          requestBody: true,
          responseBody: true,
          responseHeader: false,
          error: true,
          compact: true,
          maxWidth: 300));
    }
  }

  Future<T> get<T>({
    required String url,
    Map<String, dynamic>? params,
    CancelToken? cancelToken,
    Options? options,
  }) {
    return _requestNetwork(
        method: Method.get,
        url: url,
        queryParameters: params,
        cancelToken: cancelToken,
        options: options);
  }

  Future<T> post<T>({
    required String url,
    dynamic params,
    CancelToken? cancelToken,
    Options? options,
  }) {
    return _requestNetwork(
        method: Method.post,
        url: url,
        params: params,
        cancelToken: cancelToken,
        options: options);
  }

  Future<T> _requestNetwork<T>({
    required Method method,
    required String url,
    dynamic params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
    ProgressCallback? onSendProgress,
  }) async {
    try {
      var response = await _dio.request<String>(
        url,
        data: params,
        queryParameters: queryParameters,
        options: (options ?? Options())..method = method.value,
        onSendProgress: onSendProgress,
        cancelToken: cancelToken ?? CancelToken(),
      );
      final String data = response.data.toString();
      final Map<String, dynamic> _map = parseData(data);
      var result = LfBaseEntity<T>.fromJson(_map);
      if (result.code == 200 && result.data != null) {
        return result.data!;
      } else {
        if (result.code == 30001051) {
          var siteKey = LfBaseEntity<LfSiteKeyEntity>.fromJson(_map);
          throw NetError(result.code, siteKey.data?.siteKey ?? "");
        } else if (result.code == 30001052) {
          var factorKey = LfBaseEntity<TwoFactorEntity>.fromJson(_map);
          throw NetError(result.code, factorKey.data?.twoFactorKey ?? "");
        }
        throw NetError(result.code, result.message);
      }
    } catch (e) {
      final NetError error = ExceptionHandle.handleException(e);
      if (isTokenError(error.code)) {
        throw NetError(error.code, "");

        ///这里做一个处理,因为在TokenInterceptor中做弹窗处理了,所以不再进行额外toast 提示
      } else {
        throw error;
      }
    }
  }

  Map<String, dynamic> parseData(String data) {
    return json.decode(data) as Map<String, dynamic>;
  }
}
